package com.lrkj.payfee.factory;

import cn.hutool.core.date.DateUtil;
import com.lrkj.common.constant.FeeConstants;
import com.lrkj.common.exception.BaseException;
import com.lrkj.common.utils.LrkjDateUtil;
import com.lrkj.common.utils.NumberArithmeticUtils;
import com.lrkj.payfee.domain.ChargeNorm;
import com.lrkj.payfee.domain.ChargeTime;
import com.lrkj.payfee.domain.RoomNorm;
import com.lrkj.payfee.domain.RuleCost;
import com.lrkj.payfee.domain.vo.PayFeeVo;
import com.lrkj.payfee.vo.NormChargeVo;
import com.lrkj.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;

/***
 *
 * 费用计算工厂
 *
 * **/
@Component
public class PayFeeFactory {

    @Autowired
    private ISysConfigService configService;


    //推演 计费开始时间,计费结束时间,应收日期
    public PayFeeVo getPayFeeVo(NormChargeVo roomNorm) {
        String payFeeTemplet = configService.selectConfigByKey("payfee.templet");
        if (payFeeTemplet.equals("A")) {
            return this.payFeeTempletA(roomNorm, roomNorm.getChargeTime());
        } else if (payFeeTemplet.equals("B")) {
            return this.payFeeTempletB(roomNorm, roomNorm.getChargeTime());
        } else {
            throw new BaseException("系统参数【payfee.templet】异常,请联系管理员");
        }
    }


    public PayFeeVo payFeeTempletA(NormChargeVo roomNorm, ChargeTime chargeTime) {
        //计算,计费开始时间,计费结束时间
        PayFeeVo payFeeVo = new PayFeeVo();
        payFeeVo.setStatus(roomNorm.getStatus());
        Date beginTime = null;
        Date finishTime = null;
        if (null != roomNorm.getNextFinishChargetime()) {
            //上一次收费结束时间+1天
            beginTime = LrkjDateUtil.addDay(roomNorm.getNextFinishChargetime(), 1);
            //获取当前月的最后一天的日期
            finishTime = LrkjDateUtil.getLastMonthDay(beginTime);

        } else {
            //如果下一次开始时间为空, 也就是说是第一次绑定房屋收费标准, 直接用开始收费时间
            beginTime = roomNorm.getBeginChargeTime();
            //获取当前月的最后一天的日期
            finishTime = LrkjDateUtil.getLastMonthDay(roomNorm.getBeginChargeTime());
        }
        //如果结束收费时间小于,当前月结束收费时间,则下一次结束收费时间是  房屋标准设置 的收费接收时间
        if (null != roomNorm.getFirstFinishTime() && roomNorm.getFirstFinishTime().getTime() < finishTime.getTime()) {
            finishTime = roomNorm.getFinishChargetime();
            payFeeVo.setStatus(FeeConstants.room_norm_status_10002);
        }
        payFeeVo.setBeginTime(beginTime);
        payFeeVo.setFinishTime(finishTime);
        payFeeVo.setFirstFinishTime(finishTime);
        payFeeVo.setReceivableTime(beginTime);//应收日期
        return payFeeVo;

    }

    public PayFeeVo payFeeTempletB(NormChargeVo roomNorm, ChargeTime chargeTime) {
        //计算,计费开始时间,计费结束时间
        PayFeeVo payFeeVo = new PayFeeVo();
        //按照固定月数收取
        if (FeeConstants.charge_period_10001.equals(chargeTime.getChargePeriod())) {
            if (null != roomNorm.getNextBeginChargeTime()) {
                //上个月缴费结束日期+1天=当前月缴费开始时间
                payFeeVo.setBeginTime(LrkjDateUtil.addDay(roomNorm.getFinishChargetime(), 1));
                //获取第一个月费用结束日期-上一个月费用结束日期=相差的月数
                int difMonth = LrkjDateUtil.getDifMonth(roomNorm.getFirstFinishTime(), roomNorm.getNextFinishChargetime());
                //第一个月费用结束日期+（相差的月数+固定收取月数）= 当前月费用结束日期
                Date finishDate = LrkjDateUtil.addMonth(roomNorm.getFirstFinishTime(), difMonth + chargeTime.getMonthNum().intValue());
                finishDate = LrkjDateUtil.addDay(finishDate, -1);
                //下一次费用结束日期
                payFeeVo.setFinishTime(finishDate);
            } else {
                //如果下一次开始时间为空, 证明是第一次绑定房屋收费标准, 直接用开始收费时间
                payFeeVo.setBeginTime(roomNorm.getBeginChargeTime());
                //给开始收费时间加上固定月数,获取下一次结束收费时间
                Date finishChargeableTime = LrkjDateUtil.addMonth(roomNorm.getBeginChargeTime(), chargeTime.getMonthNum().intValue());
                finishChargeableTime = LrkjDateUtil.addDay(finishChargeableTime, -1);
                payFeeVo.setFinishTime(finishChargeableTime);
                payFeeVo.setFirstFinishTime(finishChargeableTime);
            }
        } else if (FeeConstants.charge_period_10002.equals(chargeTime.getChargePeriod())) {
            //指定月份收取 ----> 暂时不处理
        }

        return payFeeVo;
    }

    /**
     * 计算费用  自然月
     *
     * @param normChargeVo 收费标准/房屋收费标准
     * @param ruleCost     费用单
     **/
    public BigDecimal computational(RuleCost ruleCost, NormChargeVo normChargeVo) {
        //自然月
       if(normChargeVo.getChargeGenerateType().equals(FeeConstants.charge_generate_type_10)){
           return calendarMonthFee(ruleCost,normChargeVo);
       }else if(normChargeVo.getChargeGenerateType().equals(FeeConstants.charge_generate_type_20)){
           //顺延
           return postponeFee(ruleCost,normChargeVo);
       }
       return new BigDecimal(0);
    }

    //自然月计费方式
    private BigDecimal calendarMonthFee(RuleCost ruleCost, NormChargeVo normChargeVo){
        //当前月的最大天数
        int currentMonthDay = LrkjDateUtil.getCurrentMonthDay(ruleCost.getBeginTime());
        //当前月剩余天数
        int residueDay = LrkjDateUtil.daysBetween(ruleCost.getFinishTime(), ruleCost.getBeginTime()) + 1;
        //应收金额
        BigDecimal theSameMonthFee = new BigDecimal("0");

        //查看指定金额是否设置,在房屋入住的时候填写的指定金额优先级是最高的,如果有金额就不需要根据计算公式去计算金额了。
        if (null != normChargeVo.getAmountSpecified() && normChargeVo.getAmountSpecified().compareTo(BigDecimal.ZERO) > 0) {
            theSameMonthFee = normChargeVo.getAmountSpecified();
        } else {
            theSameMonthFee = this.computingFormulaMoney(normChargeVo);
        }

        //当月剩余天数不满足月
        if (residueDay != currentMonthDay) {
            theSameMonthFee = this.getReceivableMoney(currentMonthDay, residueDay, theSameMonthFee);
        }
        return theSameMonthFee.setScale(2, BigDecimal.ROUND_HALF_DOWN);
    }

    //顺延计费方式
    private BigDecimal postponeFee(RuleCost ruleCost, NormChargeVo normChargeVo){
        //应收金额
        BigDecimal theSameMonthFee = new BigDecimal("0");
        //查看指定金额是否设置,在房屋入住的时候填写的指定金额优先级是最高的,如果有金额就不需要根据计算公式去计算金额了。
        if (null != normChargeVo.getAmountSpecified() && normChargeVo.getAmountSpecified().compareTo(BigDecimal.ZERO) > 0) {
            theSameMonthFee = normChargeVo.getAmountSpecified();
        } else {
            theSameMonthFee = this.computingFormulaMoney(normChargeVo);
        }
        return theSameMonthFee.setScale(2, BigDecimal.ROUND_HALF_DOWN);
    }



    /***
     *
     * 计算应收金额
     * @param  currentMonthDay 当前月总天数
     * @param  residueDay 当前月剩余天数
     * @param money 金额
     * */
    private BigDecimal getReceivableMoney(int currentMonthDay, int residueDay, BigDecimal money) {
        //获取当前月每天的费用金额
        BigDecimal dayMoney = NumberArithmeticUtils.safeDivide(money, currentMonthDay, 14, new BigDecimal(0));
        //每天的费用相乘当前月剩余的天数
        return NumberArithmeticUtils.safeMultiply(dayMoney, residueDay);
    }

    /**
     * 通过计算公式计算费用总数
     **/
    public BigDecimal computingFormulaMoney(NormChargeVo normChargeVo) {
        BigDecimal fruitMoney = new BigDecimal("0");
        if (FeeConstants.computing_formula_10001.equals(normChargeVo.getComputingFormula())) {
            //单价*建筑面积
            fruitMoney = NumberArithmeticUtils.safeMultiply(normChargeVo.getPrices(), normChargeVo.getBuildArea());
        } else if (FeeConstants.computing_formula_10002.equals(normChargeVo.getComputingFormula())) {
            //单价*使用面积
            fruitMoney = NumberArithmeticUtils.safeMultiply(normChargeVo.getPrices(), normChargeVo.getRoomArea());
        } else if (FeeConstants.computing_formula_10003.equals(normChargeVo.getComputingFormula())) {
            //单价*总行度

        } else if (FeeConstants.computing_formula_10004.equals(normChargeVo.getComputingFormula())) {
            //指定金额
            fruitMoney = normChargeVo.getPrices();

        } else if (FeeConstants.computing_formula_10005.equals(normChargeVo.getComputingFormula())) {
            //单价
            fruitMoney = normChargeVo.getPrices();
        } else if (FeeConstants.computing_formula_10006.equals(normChargeVo.getComputingFormula())) {
            //合同单价*计价面积

        } else if (FeeConstants.computing_formula_10007.equals(normChargeVo.getComputingFormula())) {
            //合同金额

        } else if (FeeConstants.computing_formula_10010.equals(normChargeVo.getComputingFormula())) {
            //自定义公式

        }
        return fruitMoney;
    }


    /**
     * 通过计算公式计算仪表费用总数
     *
     * @param norm        房屋收费标准
     * @param chargeNorm  收费项目
     * @param chargedLine 计费行度
     **/
    public BigDecimal computingMeterMoney(RoomNorm norm, ChargeNorm chargeNorm, BigDecimal chargedLine) {
        BigDecimal fruitMoney = new BigDecimal("0");
        if (FeeConstants.computing_formula_10003.equals(chargeNorm.getComputingFormula())) {
            //单价*总行度
            fruitMoney = NumberArithmeticUtils.safeMultiply(chargeNorm.getPrices(), chargedLine);
        } else if (FeeConstants.computing_formula_10004.equals(chargeNorm.getComputingFormula())) {
            //指定金额
            fruitMoney = chargeNorm.getPrices();

        } else if (FeeConstants.computing_formula_10010.equals(chargeNorm.getComputingFormula())) {
            //自定义公式

        }
        return fruitMoney;
    }

}
